﻿using System;
using System.Diagnostics;

namespace Red.Controls.TimeLine.Core
{
    public delegate void StateChangedEventHandler( object sender, EventArgs e );

    public class TimeLineControler
    {
        public event StateChangedEventHandler StateChanged;

        #region Data

        private ScaleControler _scaleControler = new ScaleControler();
        private double _minTimeLineValue;
        private double _maxTimeLineValue;

        #endregion

        #region Ctr

        public TimeLineControler( double unit = 10.0, double max = 120 )
        {
            _scaleControler.SetUnit( unit );

            StartTime = 0.0;

            _minTimeLineValue = 0.0;
            _maxTimeLineValue = max;
            
            UpdateState();
        }
        
        #endregion

        #region Public functions

        public void MoveStartTime( double delta )
        {
            StartTime += delta;

            OnStateChanged();
        }
        
        public void Scale( double delta )
        {
            _scaleControler.AdjustIntervalSize( delta );

            bool stateChanged = UpdateState();
            if ( stateChanged )
            {
                OnStateChanged();
            }
        }

        public double ScreenOffsetToTime( double position )
        {
            Debug.Assert( position >= 0 );
            return StartTime + ( position * ( 1 / TimeToPixelRatio ) );
        }

        public double ScreenOffsetToTimeOffset( double offset )
        {
            return offset * ( 1 / TimeToPixelRatio );
        }

        public double TimeToScreenOffset( double time )
        {
            return ( time - StartTime ) * TimeToPixelRatio;
        }

        #endregion

        #region Properties

        public double StartTime { get; private set; }

        public double MinTimeLineValue
        {
            get { return _minTimeLineValue; }
            set
            {
                if ( value != _minTimeLineValue )
                {
                    _minTimeLineValue = value;
                    StateChanged( this, new EventArgs() );
                }
            }
        }

        public double MaxTimeLineValue
        {
            get { return _maxTimeLineValue; }
            set
            {
                if ( value != _maxTimeLineValue )
                {
                    _maxTimeLineValue = value;
                    StateChanged( this, new EventArgs() );
                }
            }
        }

        public double MajorIntervalUnit { get; private set; }
        public double MajorIntervalSizePx { get; private set; }
        public int MajorIntervalDivision { get; private set; }

        public double MinorIntervalUnit { get; private set; }
        public double MinorIntervalSizePx { get; private set; }

        public double IntervalSize => _scaleControler.IntervalSize;

        public double TimeToPixelRatio { get; private set;  }
        public bool IsDispalyMiddleMarkEnabled { get; private set; }

        #endregion

        #region Private functions

        private bool UpdateState()
        {
            if ( MajorIntervalUnit == _scaleControler.Unit && MajorIntervalSizePx == _scaleControler.IntervalSize )
            {
                return false;
            }

            MajorIntervalUnit = _scaleControler.Unit;
            MajorIntervalSizePx = _scaleControler.IntervalSize;
            MajorIntervalDivision = _scaleControler.Division;

            MinorIntervalSizePx = MajorIntervalSizePx / (double) MajorIntervalDivision;
            MinorIntervalUnit = MajorIntervalUnit / (double) MajorIntervalDivision;

            IsDispalyMiddleMarkEnabled = ( MajorIntervalDivision % 2 == 0 );
            TimeToPixelRatio = MajorIntervalSizePx / MajorIntervalUnit;

            return true;
        }

        private void OnStateChanged()
        {
            if ( StateChanged != null )
            {
                StateChanged( this, new EventArgs() );
            }
        }

        #endregion

        public static double SnapTime( double time )
        {
            return Math.Round( time, 3 );
        }

        public static string TimeToString( double time )
        {
            double x = SnapTime( time );
            return String.Format( "{0:0.000}s", x );
        }
    }
}
